#include <string.h>
#include <stdlib.h>
#include <stdint.h>

#include "sysflash.h"

#include "hal_tty.h"
#include "hal_config.h"
#include "systick.h"
//#include "shell.h"

params_manager_t g_config_;
static uint32_t params_flag_;

void config_params_init(void) {
    
	g_config_.node_counts = 0;
    params_flag_ = 0;
	memset(g_config_.params,0,PARAMS_MAX_NUM * sizeof(params_node_t));
}

void config_params_clear(void) {
    config_params_init();
    erase_page(CONFIG_PAGE_NUM - 1,1);
}

int config_read_params(void) {

    int params_count = 0;
    uint32_t flash_addr = CONFIG_PAGE_BASE_ADDR + (CONFIG_PAGE_NUM - 1) * CONFIG_PAGE_SIZE;
    read_flash(flash_addr,(uint8_t *)&params_count,4);
    if(params_count > PARAMS_MAX_NUM || params_count < 0) {
        params_count = 0;
    }
    g_config_.node_counts = params_count;
  
    if(params_count >= 0) {
        int flash_read_cont = params_count * sizeof(params_node_t);
        flash_addr += 4;
        read_flash(flash_addr,(uint8_t*)g_config_.params,flash_read_cont);
    } 
    params_flag_ = 0;
    return params_count;
}

int config_params_add(uint8_t *param_name,uint32_t val) {

    if(g_config_.node_counts >= PARAMS_MAX_NUM) 
		return CONFIG_PARAMS_FULL;
    
    if(strlen((char *)param_name) > PARAMS_NAME_LEN)
		return CONFIG_PARAMS_NAME_ERR;

    int param_count = g_config_.node_counts;
	g_config_.params[param_count].node_index = param_count + 1;
	memset(g_config_.params[param_count].param_name,0,PARAMS_NAME_LEN);
	memcpy(g_config_.params[param_count].param_name,param_name,strlen((char *)param_name));
	g_config_.params[param_count].value = val;
	
	g_config_.node_counts++;
    params_flag_ |= (1 << param_count);
	return param_count;
}

int config_params_set_val(uint8_t params_id,uint32_t val) {
    
    if(params_id > g_config_.node_counts) 
		return CONFIG_PARAMS_ID_ERR;

    int index = params_id - 1;
	g_config_.params[index].value = val;
    params_flag_ |= (1 << (index));

	return CONFIG_OK;
}

int config_params_reflash(void) {

    if(params_flag_ == 0)
        return CONFIG_PARAMS_IS_NOT_CHANGE;

    if(g_config_.node_counts >= PARAMS_MAX_NUM) 
		return CONFIG_PARAMS_FULL;
	
    erase_page(CONFIG_PAGE_NUM - 1,1);
    uint32_t start_addr = CONFIG_PAGE_BASE_ADDR + (CONFIG_PAGE_NUM - 1) * FMC_PAGE_SIZE;

    flash_program(start_addr,(uint32_t *)&g_config_,sizeof(g_config_));
    params_flag_ = 0;

    return CONFIG_OK;
}

int8_t get_config_id_by_name(char *name) {

    for(int i = 0; i < g_config_.node_counts;i++) {
        if(strcmp(name,(char *)g_config_.params[i].param_name) == 0) {
            return i;
        }
    }

    return CONFIG_PARAMS_NOT_FOUND;
}

int get_config_val_by_name(char *name,uint32_t *val) {
	
	if(val == NULL)
		return CONFIG_PARAMS_INVALIB;
	
	int8_t id = get_config_id_by_name(name);
	if(id < 0)
		return id;
	
	*val = g_config_.params[id].value;

	return 0;
}

int config_desplay_params(void) {

 	if(g_config_.node_counts > PARAMS_MAX_NUM) 
 		return CONFIG_READ_PARAMS_NUM_ERR;

     int count = g_config_.node_counts;
     g_tty_.printf("[Params]: %d \r\n",count);
     for(int i = 0; i < count;i++) {
         params_node_t *node = &g_config_.params[i];
         g_tty_.printf("<%d>,<%s>,<%d>:",node->node_index,node->param_name,node->value);

         if(params_flag_ & (1 << i)) {
            g_tty_.puts("True\r\n");   
         } else {
             g_tty_.puts("False\r\n");   
         }
     }
    
     return 0;
 }

#if 0

static void shell_display_params_node(SHELL_TypeDef *shell,int index) {

    params_node_t *node = &g_config_.params[index];
    shellPrint(shell,"<%d>: %s,%d,",node->node_index,node->param_name,node->value);

    if(params_flag_ & (1 << index)) {
        shellPrint(shell,"True\r\n");   
    } else {
        shellPrint(shell,"False\r\n");
    }
}

static void shell_display_params(SHELL_TypeDef *shell,int index) {
    
    int count = g_config_.node_counts;
    if(index < 0) {
        shellPrint(shell,"[Params]: %d \r\n",count);
        for(int i = 0; i < count;i++) {
            shell_display_params_node(shell,i);
        }
    } else {

        if(count > index)
            shell_display_params_node(shell,index);
    }
}

void display_params(int argc,char* argv[]) {

    SHELL_TypeDef *shell = shellGetCurrent();
    if(!shell)
        return ;

    if(argc < 2) {
        goto config_cmd_error;
    }

    if(argc >= 2) {
        if(strcmp("all",argv[1]) == 0) {
            shell_display_params(shell,-1);
            return ;
        }

        if(strcmp("reflash",argv[1]) == 0) {
            config_params_reflash();
            return;
        }

        if(strcmp("clear",argv[1]) == 0) {
            config_params_init();
            return ;
        }

        if(strcmp("display",argv[1]) == 0 && argc >= 3) {
            int count = atoi(argv[2]);
            if(count < 1 || count > g_config_.node_counts) {
                shellPrint(shell,"Param Not Found use number 1 ~ %d\r\n",g_config_.node_counts);
                return ;
            }
            shellPrint(shell,"[Params]: %d \r\n",count);
            shell_display_params_node(shell,count - 1);
            return ; 
        }

        if(strcmp("set",argv[1]) == 0 && argc >= 4) {
            int count = atoi(argv[2]);

            if(count < 1 || count > g_config_.node_counts) {
                shellPrint(shell,"Param Not Found use number 1 ~ %d\r\n",g_config_.node_counts);
                return ;
            }
            int value = atoi(argv[3]);
            config_params_set_val(count, value);

            shellPrint(shell,"[Set]: ");
            shell_display_params_node(shell,count - 1);
            return ;
        }

        if(strcmp("add",argv[1]) == 0 && argc >= 4) {
            int count = config_params_add((uint8_t *)argv[2],atoi(argv[3]));
            shell_display_params_node(shell,count);
            return ;
        }
    }

config_cmd_error:
    shellPrint(shell,"usage config <all|clear|reflash|display|set|add> ([number] [name] [value])\r\n");
    return ;
}

SHELL_EXPORT_CMD(config, display_params,Display Params Config);
#endif
